/**
 * 
 */
package wong.board.client.util;

import java.util.Set;

import wong.board.client.Board;
import wong.board.client.http.JSONRequest;
import wong.board.client.http.JSONRequest.Callback;
import wong.board.shared.ContentKeys;

import com.google.gwt.core.client.GWT;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONBoolean;
import com.google.gwt.json.client.JSONNumber;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.json.client.JSONValue;

/**
 * @author wong
 * 
 */
public class JSONTool {

	protected JSONTool() {
	}

	public static <V extends JSONValue> JSONRequest<V> getRequest(String url, Callback<V> callback) {
		JSONRequest<V> request = new JSONRequest<V>();
		request.get(url, callback);
		return request;
	}

	public static <V extends JSONValue> JSONRequest<V> getRequestFromHostPage(String path, Callback<V> callback) {
		String url = GWT.getHostPageBaseURL() + path;
		return getRequest(url, callback);
	}

	public static JSONRequest<JSONObject> requestContent(Callback<JSONObject> callback) {
		return getRequest(Board.CONTENT_URL, callback);
	}

	/**
	 * merges the <code>source</code> data into the <code>target</code> data.
	 * The <code>overwrite</code> parameter indicates whether to replace
	 * existing data in the <code>target</code>.
	 * 
	 * @param target
	 *            to put values from <code>source</code> to.
	 * @param source
	 *            to get the values for the <code>target</code>.
	 * @param overwrite
	 *            whether to overwrite value in <code>target</code> if key
	 *            already exists.
	 * @return returns <code>target</code>.
	 */
	public static JSONObject merge(JSONObject target, JSONObject source, boolean overwrite) {
		Set<String> keys = source.keySet();
		for (String key : keys) {
			if (target.containsKey(key) && !overwrite) {
				continue;
			}
			target.put(key, source.get(key));
		}
		return target;
	}

	/**
	 * merges the <code>source</code> data into the <code>target</code> data.
	 * The <code>overwrite</code> parameter indicates whether to replace
	 * existing data in the <code>target</code>.
	 * 
	 * @param target
	 *            to put values from <code>source</code> to.
	 * @param source
	 *            to get the values for the <code>target</code>.
	 * @param overwrite
	 *            whether to overwrite value in <code>target</code> if key
	 *            already exists.
	 * @return returns <code>target</code>.
	 */
	public static JSONArray merge(JSONArray target, JSONArray source, boolean overwrite) {
		int size = source.size();
		for (int i = 0; i < size; i++) {
			JSONValue value = source.get(i);
			int index = indexOf(target, value);
			if (index == -1) {
				target.set(target.size(), value);
			} else if (overwrite) {
				target.set(index, value);
			}
		}
		return target;
	}

	/**
	 * returns the index of the first found value in the <code>array</code>,
	 * that is equal to the <code>value</code> parameter or <code>-1</code>.
	 * 
	 * @param array
	 *            to search in.
	 * @param value
	 *            to look for.
	 * @return the index of the value or <code>-1</code>.
	 */
	public static int indexOf(JSONArray array, JSONValue value) {
		int size = array.size();
		for (int i = 0; i < size; i++) {
			if (array.get(i).toString().equals(value.toString())) {
				return i;
			}
		}
		return -1;
	}

	//

	public static String toString(JSONObject object, String pairDelimiter, String keyValueDelimiter) {
		if (object != null) {
			String string = "";
			String pd = "";
			Set<String> properties = object.keySet();
			for (String property : properties) {
				String value = object.get(property).isString().stringValue();
				string += pd + property + keyValueDelimiter + value;
				pd = pairDelimiter;
			}
			return string;
		}
		return null;
	}

	//

	public static JSONArray isArray(JSONObject object, String key) {
		return object.containsKey(key) ? object.get(key).isArray() : null;
	}

	public static JSONObject isObject(JSONObject object, String key) {
		return object.containsKey(key) ? object.get(key).isObject() : null;
	}

	public static JSONBoolean isBoolean(JSONObject object, String key) {
		return object.containsKey(key) ? object.get(key).isBoolean() : null;
	}

	public static JSONNumber isNumber(JSONObject object, String key) {
		return object.containsKey(key) ? object.get(key).isNumber() : null;
	}

	public static JSONString isString(JSONObject object, String key) {
		return object.containsKey(key) ? object.get(key).isString() : null;
	}

	public static String stringValue(JSONObject object, String key) {
		return object.containsKey(key) ? object.get(key).isString().stringValue() : null;
	}

	//

	public static JSONArray isArray(JSONObject object, ContentKeys key) {
		return isArray(object, key.toString());
	}

	public static JSONObject isObject(JSONObject object, ContentKeys key) {
		return isObject(object, key.toString());
	}

	public static JSONBoolean isBoolean(JSONObject object, ContentKeys key) {
		return isBoolean(object, key.toString());
	}

	public static JSONNumber isNumber(JSONObject object, ContentKeys key) {
		return isNumber(object, key.toString());
	}

	public static JSONString isString(JSONObject object, ContentKeys key) {
		return isString(object, key.toString());
	}

	public static String stringValue(JSONObject object, ContentKeys key) {
		return stringValue(object, key.toString());
	}

}
